const Pedding = "Pedding";
const Resolved = "Resolved";
const Rejected = "Rejected";

function Promise(excutor) {
    this.data = null;
    this.status = Pedding;
    this.resolveHandlers = [];
    this.rejectHandles = [];

    const callResolveHandles = (val) => {
        while (this.resolveHandlers.length) {
            const thenHandler = this.resolveHandlers.pop();
            thenHandler(val);
        }
    }
    const callRejectHandlers = (reason) => {
        while (this.rejectHandles.length) {
            const reject = this.rejectHandles.pop();
            reject(reason);
        }
    }
    excutor(callResolveHandles, callRejectHandlers);
}
Promise.prototype.then = function (resovleThen, rejectThen) {
    resovleThen = resovleThen ? resovleThen : () => { };
    rejectThen = rejectThen ? rejectThen : () => { };
    if (this.status === Pedding) {
        return new Promise((resolve, reject) => {
            const doResolve = (value) => {
                this.data = value;
                this.status = Resolved;
                const s = resovleThen(value);
                if (s instanceof Promise) {
                    s.then(resolve, reject);
                } else {
                    resolve(s);
                }
            }
            this.resolveHandlers.push(doResolve);
            const doReject = (reason) => {
                this.data = reason;
                this.status = Rejected;
                const s = rejectThen(reason);
                if (s instanceof Promise) {
                    s.then(resolve, reject);
                } else {
                    reject(s);
                }
            }
            this.rejectHandles.push(doReject);
        });
    } else if (this.status === Resolved) {
        return new Promise((resolve, reject) => {
            const s = resovleThen(this.data);
            if (s instanceof Promise) {
                s.then(resolve, reject);
            } else {
                resolve(s);
            }
        });
    } else {
        return new Promise((resolve, reject) => {
            const s = rejectThen(this.data);
            if (s instanceof Promise) {
                s.then(resolve, reject);
            } else {
                reject(s);
            }
        });
    }
}
Promise.prototype.catch = (rejector) => {
    return this.then(null, rejector);
}

Promise.prototype.finally = (onDone) => {
    return this.then(onDone, onDone);
}

Promise.resolve = (input) => {
    if (input instanceof Promise) return resolvor;
    return new Promise((resolve) => {
        resolve(input);
    });
}

Promise.reject = (input) => {
    if (input instanceof Promise) return input;
    return new Promise((undefined, reject) => {
        reject(input);
    })
}

Promise.all = (arr) => {
    const resArr = [];
    const count = arr.length;
    return new Promise((resolve, reject) => {
        for (let p of arr) {
            p.then(res => {
                resArr.push(res);
                if (resArr.length === count) {
                    resolve(resArr);
                }
            })
        }
    })
}

Promise.race = (arr) => {
    const resArr = [];
    return new Promise((resolve, reject) => {
        for (let p of arr) {
            p.then(res => {
                resArr.push(res);
                if (resArr.length === 1) {
                    resolve(resArr[0]);
                }
            })
        }
    })
}

//以下都是测试用代码
// const p = new Promise((resolve, reject) => {
//     setTimeout(() => {
//         resolve({ name: "eric", age: 19 });
//     }, 0);
// })

// p.then(res => {
//     console.log(res);
//     return new Promise((resolve, reject) => {
//         setTimeout(() => {
//             resolve({ message: "this is the returned Promise" });
//         }, 1000);
//     })
// }).then(res => {
//     console.log(res);
//     return { type: "simple res, not Promise" };
// }).then(res => {
//     console.log(res);
// })

const p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve({ name: "eric 100", age: 100 });
    }, 100);
})
const p2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve({ name: "eric 1000", age: 1000 });
    }, 1000);
})
const p3 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve({ name: "eric 1500", age: 1500 });
    }, 1500);
})

Promise.all([p1, p2, p3]).then(res => {
    console.log("all", res);
})
Promise.race([p1, p2, p3]).then(res => {
    console.log("race", res);
})

